#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2019/1/16 12:03
# @Author  : xiaodai
import os
import cv2
#from skimage.measure import compare_ssim
from skimage.metrics import structural_similarity as compare_ssim 
import shutil
import datetime
from common.utils import *

# 均值哈希算法
def ahash(image):
    # 将图片缩放为8*8的
    image =  cv2.resize(image, (8,8), interpolation=cv2.INTER_CUBIC)
    # 将图片转化为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    # s为像素和初始灰度值，hash_str为哈希值初始值
    s = 0
    ahash_str = ''
    # 遍历像素累加和
    for i in range(8):
        for j in range(8):
            s = s+gray[i, j]
    # 计算像素平均值
    avg = s/64
    # 灰度大于平均值为1相反为0，得到图片的平均哈希值，此时得到的hash值为64位的01字符串
    ahash_str  = ''
    for i in range(8):
        for j in range(8):
            if gray[i,j]>avg:
                ahash_str = ahash_str + '1'
            else:
                ahash_str = ahash_str + '0'
    result = ''
    for i in range(0, 64, 4):
        result += ''.join('%x' % int(ahash_str[i: i + 4], 2))
    # print("ahash值：",result)
    return result
 
# 差异值哈希算法
def dhash(image):
    # 将图片转化为8*8
    image = cv2.resize(image,(9,8),interpolation=cv2.INTER_CUBIC )
    # 将图片转化为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    dhash_str = ''
    for i in range(8):
        for j in range(8):
            if gray[i,j]>gray[i, j+1]:
                dhash_str = dhash_str + '1'
            else:
                dhash_str = dhash_str + '0'
    result = ''
    for i in range(0, 64, 4):
        result += ''.join('%x'%int(dhash_str[i: i+4],2))
    # print("dhash值",result)
    return result
 

def pHash(img):
    # 感知哈希算法
    # 缩放32*32
    img = cv2.resize(img, (32, 32))   # , interpolation=cv2.INTER_CUBIC

    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 将灰度图转为浮点型，再进行dct变换
    dct = cv2.dct(np.float32(gray))
    # opencv实现的掩码操作
    dct_roi = dct[0:8, 0:8]

    hash = []
    avreage = np.mean(dct_roi)
    for i in range(dct_roi.shape[0]):
        for j in range(dct_roi.shape[1]):
            if dct_roi[i, j] > avreage:
                hash.append(1)
            else:
                hash.append(0)

    return ''.join(str(x) for x in hash)

# 计算两个哈希值之间的差异
def campHash(hash1, hash2):
    n = 0
    # hash长度不同返回-1,此时不能比较
    if len(hash1) != len(hash2):
        return -1
    # 如果hash长度相同遍历长度
    for i in range(len(hash1)):
        if hash1[i] != hash2[i]:
            n = n+1
    return n

ccc = (256, 256)

def imsim(img1, img2, sz = (256, 256)):
    img1 = cv2.resize(img1, sz, interpolation=cv2.INTER_CUBIC)
    img2 = cv2.resize(img2, sz, interpolation=cv2.INTER_CUBIC)
    ssim = compare_ssim(img1, img2, multichannel=True)
    return ssim

def findrep(im, fnlist, thd):
    replist = []
    for fn2 in fnlist:
        im2 = cv2.imread(fn2)
        s = imsim(im, im2)
        if s>thd:
            replist.append(fn2)
            break

    return replist


import json

imhash = pHash
 
def calc_hash(img_files):
    hashlist = {}
    replist = []
    for i in range(len(img_files)):
        fn = img_files[i]
        im = cv2.imread(fn)
        h = imhash(im)
        print(i, fn)
        if h in hashlist.keys():
            hashlist[h].append(fn)
        else:
            hashlist[h] = [fn]
    
    return hashlist

hashlist_json_fn = 'hashlist.json'

def findrep2(fnlist, thd):
    replist = []
    ims = []
    n = len(fnlist)
    for i in range(n):
        fn1 = fnlist[i]
        img1 = cv2.imread(fn1)
        img1 = cv2.resize(img1, ccc, interpolation=cv2.INTER_CUBIC)
        ims.append(img1)

    for i in range(n):
        for j in range(i+1, n):
            ssim = imsim(ims[i], ims[j], (256, 256))
            if ssim>thd:
                replist.append((fnlist[i], fnlist[j], ssim))
                break

    return replist


def calc_replist(img_files, thd):
    if os.path.exists(hashlist_json_fn):
        hashlist = json.load(open(hashlist_json_fn, 'r'))
    else:
        hashlist = calc_hash(img_files)
        open(hashlist_json_fn, 'w').write(json.dumps(hashlist))

    replist = []
    for h in hashlist.keys():
        fnlist = hashlist[h]
        if len(fnlist)>1:
            print(fnlist)
            replist+=findrep2(fnlist, thd)
    
    return replist

replist_json_fn = 'replist.json'

import numpy as np

def immageh(ims):
    h = 0
    w = 0
    for im in ims:
        h = max(h, im.shape[0])
        w += im.shape[1]

    # new image
    final_matrix = np.zeros((h, w, 3), np.uint8)
    
    x = 0
    for im in ims:
        final_matrix[0:im.shape[0], x:(x+im.shape[1]),:] = im
        x += im.shape[1]
    
    return final_matrix

def immagev(ims):
    h = 0
    w = 0
    for im in ims:
        w = max(h, im.shape[1])
        h += im.shape[0]

    # new image
    final_matrix = np.zeros((h, w, 3), np.uint8)
    
    x = 0
    for im in ims:
        final_matrix[x:(x+im.shape[0]), 0:(im.shape[1]),:] = im
        x += im.shape[0]
    
    return final_matrix

def ren(fn1, fn2):
    _, fn21 = os.path.split(fn2)
    fn22 = '%s_@_%s'%(fn1, fn21)
    os.rename(fn2, fn22)

def showimgs(name, fnlist):
    ims = []
    for fn1 in fnlist:
        im1 = cv2.imread(fn1)
        ims.append(im1)

    im = immageh(ims)
    cv2.namedWindow(name, 0)
    cv2.imshow(name, im)

def delsim(img_files, thd):
    if os.path.exists(replist_json_fn):
        replist = json.load(open(replist_json_fn, 'r'))
    else:
        replist = calc_replist(img_files, thd)
        open(replist_json_fn, 'w').write(json.dumps(replist))

    replist.sort(key=lambda x: x[2], reverse=True)

    cv2.namedWindow('img', 0)
    for fn1, fn2, ssim in replist:
        if os.path.exists(fn1) and os.path.exists(fn2):
            print(fn1, fn2, ssim)
            if ssim>0.999:
                ren(fn1, fn2)
                continue
                
            #cv2.imshow('img', im)
            #showimgs([fn1, fn2])
            c = cv2.waitKey(-1)
            c = chr(c)
            if 'd' == c:
                ren(fn1, fn2)

    return replist


def move_file(filename1,filename2):
    shutil.move(filename1,filename2)

def delete(filename1):
    #os.remove(filename1)
    print('del:', filename1)

def findrep1(im, fnlist, thd):
    replist = []
    n = len(fnlist)
    img2 = cv2.resize(im, ccc, interpolation=cv2.INTER_CUBIC)
    for i in range(n):
        fn1 = fnlist[i]
        if not os.path.exists(fn1):
            continue
        img1 = cv2.imread(fn1)
        if img1 is None:
            continue
        img1 = cv2.resize(img1, ccc, interpolation=cv2.INTER_CUBIC)
        ssim = compare_ssim(img1, img2, multichannel=True)
        if ssim>thd:
            replist.append((fn1, ssim))

    replist.sort(key=lambda x: x[1], reverse=True)
    return replist

class SimPicFinder:
    def __init__(self):
        self.hash = {}
        pass

    def get_sim(self, fn, thd=0.9):
        im = cv2.imread(fn)
        h = imhash(im)
        out = []
        if h in self.hash.keys():
            out = findrep1(im, self.hash[h], thd)
        else:
            self.hash[h] = [fn]
        
        return out


def test_SimPicFinder():
    img_path = 'F:/data/deepblue/201106喜诺试剂瓶/snap/200_snap2'
    os.chdir(img_path)
    #img_files = [os.path.join(rootdir, file) for rootdir, _, files in os.walk('./') for file in files if
    #                (file.endswith('.jpg'))]
    img_files = listdir('./', ['.jpg', '.jpeg'])

    #img_files = img_files[:6]
    #showimgs('asdfaf', img_files)
    #cv2.waitKey(-1)
    mkdir('out')
    sf = SimPicFinder()
    for fn in img_files:
        rep = sf.get_sim(fn)
        if len(rep)>0:
            #for i in range(len(rep)):
            #print(rep[i])
            #fn0 = rep[i][0]
            print(f'-- {fn} -> {rep[0][0]}')
            pa, fn1 = os.path.split(fn)
            move_file(fn, f'out/{fn1}')
        else:
            print(fn)

    return 


def test_delsim():
    img_path = 'F:/data/deepblue/201106喜诺试剂瓶/snap/200_snap'
    # save_path_img = r'F:\temp\demo_save'
    # os.makedirs(save_path_img, exist_ok=True)
    os.chdir(img_path)
    imgs_n = []
    num = []
    del_list = []
    img_files = [os.path.join(rootdir, file) for rootdir, _, files in os.walk('./') for file in files if
                    (file.endswith('.jpg'))]

    for fn in img_files:
        if '@' in fn:
            fn2 = fn.split('@')[-1]
            fn3 = fn2[1:]
            fn3 = fn3.replace('.jpg_deleted.jpg', '.jpg')
            os.rename(fn, fn3)
            fn = fn3

    replist = delsim(img_files, 0.95)

if __name__ == '__main__':
    test_SimPicFinder()